﻿using System;
using System.Globalization;
using Foxit.PDF;
using Foxit.PDF.PageElements;

namespace Sustainalytics.Reporting.Framework
{
    public class BulletScoreAndAssessment : IPdfPageElement
    {
        public float Left { get; set; }
        public float LeftOffset { get; set; }
        public float Top { get; set; }
        public int Row { get; set; }
        public int Column { get; set; }
        public Page Page { get; set; }
        public Group PageElements { get; set; }

        public RgbColor Color { get; set; }
        
        public string Name { get; set; }
        public Font NameFont { get; set; }
       
        public int Value { get; set; }
        public Font ValueFont { get; set; }
        public int Count { get; set; }

        public string Assessment { get; set; }
        public Font AssessmentFont { get; set; }
        public bool HasAssessmentTable { get; set; }
        public string[] Assessments { get; set; }

        public bool IsPercentile { get; set; }
        public bool IsRelativePosition { get; set; }
        public bool IsInReferenceUniverse { get; set; }

        private readonly string _NaN = "N/A";
        public const int NoValue = -1;

        public BulletScoreAndAssessment()
        {
            IsRelativePosition = false;
            IsPercentile = false;
            HasAssessmentTable = false;
            IsInReferenceUniverse = true;
        }

        public void Draw()
        {
            const float radius = 17.5f;
            const float borderWidth = 0.5f;
            var valueFontSize = 24f;

            var valueColor = RgbColor.White;
            if (!IsInReferenceUniverse)
                valueColor = RgbColor.Red;

            Page.Elements.Add(
                new Circle(Left + radius, Top + radius, radius, radius, Color, Color, borderWidth, LineStyle.Solid));

            const float labelWidth = radius*2;
            var lebelHeigth = valueFontSize + 2f;
            var labelTopOffset = (radius*2 - valueFontSize)/2 + 1f;

            if (IsRelativePosition)
            {
                if (Value <= NoValue)
                {
                    valueFontSize = 18f;

                    Page.Elements.Add(PageElementForNA(labelTopOffset + 2f, labelWidth, lebelHeigth, valueFontSize, valueColor));
                }
                else
                {
                    Page.Elements.Add(
                     new Label(Value.ToString(CultureInfo.InvariantCulture),
                         Left, Top + 1f, 35f, 16f, ValueFont, 14, TextAlign.Center, valueColor));
                    Page.Elements.Add(
                        new Label("out of",
                            Left, Top + 13, 35f, 10f, ValueFont, 8, TextAlign.Center, valueColor));
                    Page.Elements.Add(
                        new Label(Count.ToString(CultureInfo.InvariantCulture),
                            Left, Top + 21f, 35f, 16f, ValueFont, 14, TextAlign.Center, valueColor));
                }
            }

            if (IsPercentile)
            {
                var leftOffset = 0.0f;
                var topOffset = 0.0f;
                var suffixOffset = 28f;
                valueFontSize = 20f;

                var percentile = Value;

                if (percentile == 0)
                {
                    leftOffset = 0f;
                    topOffset = 2f;
                }

                if (percentile == 100)
                {
                    valueFontSize = 18f;
                    topOffset = 5f;
                }

                if (percentile > 0 && percentile < 10)
                {
                    leftOffset = -2f;
                    valueFontSize = 24f;
                    suffixOffset = 25f;
                }

                if (percentile >= 10 && percentile < 100)
                {
                    leftOffset = -3f;
                    topOffset = 2f;
                }

                if (Value <= NoValue)
                {
                    valueFontSize = 18f;

                    Page.Elements.Add(new Label(_NaN,
                      Left + leftOffset, Top + labelTopOffset + topOffset + 2f, labelWidth, lebelHeigth, ValueFont, valueFontSize, TextAlign.Center, valueColor));
                }
                else
                {
                    Page.Elements.Add(
                  new Label(Value.ToString(CultureInfo.InvariantCulture),
                      Left + leftOffset, Top + labelTopOffset + topOffset, labelWidth, lebelHeigth, ValueFont, valueFontSize, TextAlign.Center, valueColor));

                    Page.Elements.Add(
                        new Label(OrdinalNumberSuffix(Value),
                            Left + leftOffset + suffixOffset, Top + labelTopOffset + 3f, 20f, 9f, ValueFont, 7, TextAlign.Left, valueColor));
                }
            }

            if (!IsRelativePosition && !IsPercentile)
            {
                Page.Elements.Add(
                    new Label(Value.ToString(CultureInfo.InvariantCulture), 
                        Left, Top + labelTopOffset, labelWidth, lebelHeigth, ValueFont, valueFontSize, TextAlign.Center, RgbColor.White));
            }

            const float nameLeftOffset = 45f;

            Page.Elements.Add(
                new Label(Name, Left + nameLeftOffset, Top + 3f, 250f, 15f, NameFont, 10, TextAlign.Left, RgbColor.Black));
            Page.Elements.Add(
                new Line(Left + nameLeftOffset, Top + 15f, Left + 140f, Top + 15f, 0.5f, RgbColor.Black));

            const float assessmentLeftOffset = 45f;
            const float assessmentTopOffset = 20f;
            const float assessmentFontSize = 7f;

            if (HasAssessmentTable)
            {
                const float tableHeight = 50f;
                const float rowHeight = 8f;
                const float columnWidth = 100f;

                var table = new Table(Left + assessmentLeftOffset, Top + assessmentTopOffset, columnWidth, tableHeight, AssessmentFont, assessmentFontSize);
                table.Border.Width = 0.0f;
                table.CellSpacing = 0.0f;
                table.CellDefault.Align = TextAlign.Left;
                table.CellDefault.VAlign = VAlign.Top;
                table.CellDefault.Padding.Value = 0.0f;
                table.CellDefault.Border.Color = RgbColor.Blue;
                table.CellDefault.Border.Width = 0.0f;
                table.CellDefault.Border.LineStyle = LineStyle.None;
                table.Border.Color = Grayscale.Black;
                table.RepeatColumnHeaderCount = 0;
                table.RepeatRowHeaderCount = 0;
                table.Columns.Add(columnWidth);

                foreach (var assessment in Assessments)
                {
                    var row = table.Rows.Add(rowHeight);
                    if (assessment == Assessment)
                        row.Cells.Add(assessment, Fonts.CalibriRegular, assessmentFontSize + 1f, RgbColor.Black, RgbColor.White, 1);
                    else
                        row.Cells.Add(assessment, AssessmentFont, assessmentFontSize, RgbColor.DimGray, RgbColor.White, 1);
                }

                Page.Elements.Add(table);
            }
            else
            {
                var assessment = Assessment ?? string.Empty;
                
                Page.Elements.Add(
                    new Label(assessment, Left + assessmentLeftOffset, Top + assessmentTopOffset, 100f, 10f, AssessmentFont, 8, TextAlign.Left, RgbColor.Black));
            }
        }

        private Label PageElementForNA(float labelTopOffset, float labelWidth, float lebelHeigth, float valueFontSize, RgbColor valueColor)
        {
            return new Label(_NaN,
                Left, Top + labelTopOffset, labelWidth, lebelHeigth, ValueFont, valueFontSize, TextAlign.Center, valueColor);
        }

        public static string OrdinalNumberSuffix(int number)
        {
            string suffix = string.Empty;

            if (number < 1)
                return suffix;

            int ones = number % 10;
            int tens = (int)Math.Floor(number / 10f) % 10;

            if (tens == 1)
            {
                suffix = "th";
            }
            else
            {
                switch (ones)
                {
                    case 1:
                        suffix = "st";
                        break;

                    case 2:
                        suffix = "nd";
                        break;

                    case 3:
                        suffix = "rd";
                        break;

                    default:
                        suffix = "th";
                        break;
                }
            }

            return suffix;
        }
    }
}
